package cn.edu.sjtu.se.dslab.component.design.generate;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import cn.edu.sjtu.se.dslab.component.design.DesignPatternComponent;
import cn.edu.sjtu.se.dslab.component.design.DesignPatternType;
import cn.edu.sjtu.se.dslab.component.dp.parse.DesignPatternInstanceBean;
import cn.edu.sjtu.se.dslab.component.dp.parse.Property;
import cn.edu.sjtu.se.dslab.component.method.ComponentInterface;
import cn.edu.sjtu.se.dslab.component.method.MethodComponent;
import cn.edu.sjtu.se.dslab.component.method.util.MethodComponentUtil;
import cn.edu.sjtu.se.dslab.helper.ApplicationContextHelpler;
import cn.edu.sjtu.se.dslab.project.Project;
import cn.edu.sjtu.se.dslab.project.ProjectMethod;
import cn.edu.sjtu.se.dslab.service.IComponentService;
import cn.edu.sjtu.se.dslab.service.IDesignPatternComponentService;
import cn.edu.sjtu.se.dslab.service.IMethodComponentService;
import cn.edu.sjtu.se.dslab.service.IProjectMethodService;
import cn.edu.sjtu.se.dslab.service.IProjectService;
import cn.edu.sjtu.se.dslab.util.DateUtil;
import cn.edu.sjtu.se.dslab.util.FileUtil;
import cn.edu.sjtu.se.dslab.util.PackUtil;

public class DesignPatternCodeUtil {
	private static Logger logger = LoggerFactory.getLogger(DesignPatternCodeUtil.class);
	private static final String CASF_DIR = "CASF";
	private static final String APP_DIR = "App";

	IProjectService projectService;

	IDesignPatternComponentService designPatternComponentService;

	TaskCodeGenerator taskCodeGenerator;
	BusDpcCodeGenerator busGenerator;
	KeyCodeGenerator keyCodeGenerator;
	IODpcCodeGenerator ioGenerator;
	EntityZoneGenerator entityZoneGenerator;
	
	DisplayZoneGenerator displayZoneGenerator;

	IMethodComponentService methodComponentService;

	IComponentService componentService;

	MethodComponentUtil methodComponentUtil;
	
	IProjectMethodService projectMethodService;
	


	private long projectId;
	private boolean isSimulation = true;

	public DesignPatternCodeUtil(long projectId) {
		this.projectId = projectId;
		projectService = (IProjectService) ApplicationContextHelpler
				.getBean("projectService");
		designPatternComponentService = (IDesignPatternComponentService) ApplicationContextHelpler
				.getBean("designPatternComponentService");
		methodComponentService = (IMethodComponentService) ApplicationContextHelpler
				.getBean("methodComponentService");
		
		projectMethodService = (IProjectMethodService)ApplicationContextHelpler.getBean("projectMethodService");

		// busGenerator =
		// (BusDpCodeGenerator)ApplicationContextHelpler.getBean("busDpCodeGenerator");
		taskCodeGenerator = (TaskCodeGenerator)ApplicationContextHelpler
				.getBean("taskCodeGenerator");
		
		busGenerator = (BusDpcCodeGenerator) ApplicationContextHelpler
				.getBean("busDpcCodeGenerator");
		keyCodeGenerator = (KeyCodeGenerator) ApplicationContextHelpler
				.getBean("keyCodeGenerator");
		ioGenerator = (IODpcCodeGenerator) ApplicationContextHelpler
				.getBean("ioDpcCodeGenerator");
		entityZoneGenerator = (EntityZoneGenerator) ApplicationContextHelpler
				.getBean("entityZoneGenerator");
		methodComponentUtil = (MethodComponentUtil) ApplicationContextHelpler
				.getBean("methodComponentUtil");
		
		displayZoneGenerator = (DisplayZoneGenerator)ApplicationContextHelpler
				.getBean("displayZoneGenerator");

	}
	
	public String generateRealMachineCode()throws IOException{
		this.isSimulation = false;
		return generateDesignPatternCode();
	}

	public String generateDesignPatternCode() throws IOException {
		Project project = projectService.getProjectById(projectId);

		String dateString = DateUtil
				.getDateAsFileNameString(DateUtil.COMMON_DATE_PATTERN);
		// the relative directory path
		StringBuffer targetFolderPath = new StringBuffer();
		targetFolderPath.append(project.getFolderPath()).append("code/")
				.append(dateString).append("/");
		logger.info(targetFolderPath.toString());
		// create the target dir
		FileUtil.createDirectorys(targetFolderPath.toString());

		// copy the initial to the target directory;
		copyInitFiles(targetFolderPath.toString());
		
		//generte the task code
		taskCodeGenerator.generateCode(targetFolderPath.toString(), project, null);

		// generate the bus design pattern component code
		DesignPatternComponent busDpc = designPatternComponentService
				.getDesignPatternCommponentByType(projectId,
						DesignPatternType.BUS);
		DesignPatternInstanceBean busDpiBean = new DesignPatternInstanceBean(
				DesignPatternType.BUS, busDpc.getXmlPath());
		// relative path
		busGenerator.generateCode(targetFolderPath.toString(), project, busDpiBean);
		keyCodeGenerator.generateCode(targetFolderPath.toString(), project);
		entityZoneGenerator.generateCode(targetFolderPath.toString(), project);
		
		//generate the displayZone file
		displayZoneGenerator.generateCode(targetFolderPath.toString(), project);

		// generate the io design pattern component code
		DesignPatternComponent displayDpc = designPatternComponentService
				.getDesignPatternCommponentByType(projectId,
						DesignPatternType.DISPLAY);
		DesignPatternInstanceBean displayDpiBean = new DesignPatternInstanceBean(
				DesignPatternType.DISPLAY, displayDpc.getXmlPath());

		DesignPatternComponent controlDpc = designPatternComponentService
				.getDesignPatternCommponentByType(projectId,
						DesignPatternType.CONTROL);
		DesignPatternInstanceBean controlDpiBean = new DesignPatternInstanceBean(
				DesignPatternType.CONTROL, controlDpc.getXmlPath());

		List<Property> functionProperties = controlDpiBean
				.getPropertyByName("control_function");
		Set<String> dependencyFileSet = new HashSet<String>();
		for (Property p : functionProperties) {
			logger.info("Function IDs" + p.getValue());
			String[] link = p.getValue().split("=");
			MethodComponent methodComponent = methodComponentService
					.getMethodComponentByUri(link[1]);
			Map<String, String> dependFiles = methodComponentUtil
					.getMethodComponentFileList(methodComponent);
			dependencyFileSet.addAll(dependFiles.values());
		}
		//拷贝需要下载的methodComponent,显示的函数组件放到devices目录下
		Set<String> displayDependecyFilSet = new HashSet<String>();
		List<ProjectMethod> projectMethods = projectMethodService.getListByProject(project);
		for (ProjectMethod pm : projectMethods){
			logger.info("ProjectMethod " + pm.getId());
			if (pm.getMethodComponent() != null){
					Map<String, String> dependFiles = methodComponentUtil
						.getMethodComponentFileListWithoutDepend(pm.getMethodComponent());
					if (pm.getMethodComponent().getCinterface().getItype().equals(ComponentInterface.INTERFACE_TYPE_INFO)){
					displayDependecyFilSet.addAll(dependFiles.values());
				}else{
					dependencyFileSet.addAll(dependFiles.values());
				}
			}
		}
		
		// copy dependency files to the folder
		for (String f : dependencyFileSet) {
			logger.info("Depend " + f);
			// 把依赖的文件复制到生成代码的文件夹下
			FileUtil.copyFile(f, FileUtil.getRootPath() + targetFolderPath.toString()+ "App/", null);
		}
		for (String f : displayDependecyFilSet) {
			logger.info("Display Depend " + f);
			// 把依赖的文件复制到生成代码的文件夹下
			FileUtil.copyFile(f, FileUtil.getRootPath() + targetFolderPath.toString()+ "Devices/", null);
		}
		

		for (Property p : displayDpiBean.getPropertyByName("page_name")) {
			ViewCodeGenerator viewCodeGenerator = new ViewCodeGenerator(
					p.getValue());
			viewCodeGenerator.generateCode(targetFolderPath.toString(), null,
					displayDpiBean, controlDpiBean);
		}

		// generate the io design pattern code
		DesignPatternComponent ioDpc = designPatternComponentService
				.getDesignPatternCommponentByType(projectId,
						DesignPatternType.IO);
		DesignPatternInstanceBean ioDpiBean = new DesignPatternInstanceBean(
				DesignPatternType.IO, ioDpc.getXmlPath());
		ioGenerator.generateCode(targetFolderPath.toString(), null, ioDpiBean); 

		// the the initial running architecture
		MethodComponent component = methodComponentService
				.getMethodComponentByUri("component:method_component:38070E44");

		List<String> sourceFileList = new ArrayList<String>();
		if (component != null) {
			MethodComponentUtil util = new MethodComponentUtil();
			Map<String, String> fileMap = util
					.getMethodComponentFileList(component);
			// 包含所有的依赖文件的绝对路径
			// sourceFileList.addAll(fileMap.values());
			for (String f : sourceFileList) {
				// logger.debug(f);
			}
		}
		
		// pack the code into zip file
		String sourceDirPath = FileUtil.getRootPath() + targetFolderPath;
		// sourceFileList.addAll(FileUtil.getFileAbsolutePathList(sourceDirPath));
		String zipFilePath = FileUtil.getRootPath() + project.getFolderPath()
				+ "code/";
		String zipFileName = "code-" + dateString + ".zip";

		// PackUtil.zipList(sourceFileList, zipFilePath, zipFileName);
		PackUtil.zip(sourceDirPath, zipFilePath, zipFileName);
		logger.info("Source Dir Path: " + sourceDirPath);
		logger.info("Zip file Path:" + zipFilePath);
		logger.info("zipF file Name:" + zipFileName);
		return zipFilePath + zipFileName;
	}

	public void copyInitFiles(String targetDirPath) throws IOException {
		String AppPath = FileUtil.getRootPath() + "systemdata/initial/App";
		String CASFPath = FileUtil.getRootPath() + "systemdata/initial/CASF";

		String CASFConfigsSimuPath = FileUtil.getRootPath()
				+ "systemdata/initial/CASFConfigs_Simu";
		String CASFConfigsZ19Path = FileUtil.getRootPath()
				+ "systemdata/initial/CASFConfigs_Z19";

		String DevicesSimuPath = FileUtil.getRootPath()
				+ "systemdata/initial/Devices_Simu";
		String DevicesZ19Path = FileUtil.getRootPath()
				+ "systemdata/initial/Devices_Z19";
		String EntitiesPath = FileUtil.getRootPath()
				+ "systemdata/initial/Entities";

		targetDirPath = FileUtil.getRootPath() + targetDirPath;
		logger.info("target Dir:" + targetDirPath);
		FileUtil.copyDir(AppPath, targetDirPath, null);
		FileUtil.copyDir(CASFPath, targetDirPath, null);
		FileUtil.copyDir(EntitiesPath, targetDirPath, null);

		if (isSimulation) {
			FileUtil.copyDir(CASFConfigsSimuPath, targetDirPath, "CASFConfigs");
			FileUtil.copyDir(DevicesSimuPath, targetDirPath, "Devices");
		}else{
			FileUtil.copyDir(CASFConfigsZ19Path, targetDirPath, "CASFConfigs");
			FileUtil.copyDir(DevicesZ19Path, targetDirPath, "Devices");
		}
	}
}








